// Copyright (c) Microsoft
// All rights reserved
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.

/// <summary>Using array with CPU access type none on accelerator supporting zero-copy</summary>
// RUN: %amp_device -D__GPU__ %s -m32 -emit-llvm -c -S -O3 -o %t.ll && mkdir -p %t
// RUN: %llc -march=c -o %t/kernel_.cl < %t.ll

#include <amp.h>
#include "../Common.h"
#include "../../../../amp.data.h"
#include "../../../../../device.h"

using namespace Concurrency;
using namespace Concurrency::Test;

int test1()
{
	extent<2> arr_extent = CreateRandomExtent<2>(64);
    	array<float, 2> arr(arr_extent);
	
    return VerifyCpuAccessType(arr, access_type_read_write);
}

int test2()
{
	array<int, 1> arr1(64);
	array<int, 2> arr2(64, 64);
	array<int, 3> arr3(64, 64, 64);
	
    int res;
	
    res &=VerifyCpuAccessType(arr1, access_type_read_write);
    res &= VerifyCpuAccessType(arr2, access_type_read_write);
    res &= VerifyCpuAccessType(arr3, access_type_read_write);
	
	return res;
}

int test3()
{
	extent<3> arr_extent = CreateRandomExtent<3>(64);  
	std::vector<int> cont(arr_extent.size(), 10);
	array<int, 3> arr(arr_extent, cont.begin());
	
    return VerifyCpuAccessType(arr, access_type_read_write);
}

int test4()
{
	extent<2> arr_extent = CreateRandomExtent<2>(64);  
	std::vector<int> cont(arr_extent.size(), 10);
	array<int, 2> arr(arr_extent, cont.begin(), cont.end());
	
    return VerifyCpuAccessType(arr, access_type_read_write);
}

int test5()
{
	std::vector<int> cont1(64, 10);
	array<int, 1> arr1(64, cont1.begin());
	
	std::vector<int> cont2(64 * 64, 10);
	array<int, 2> arr2(64, 64, cont2.begin());
	
	std::vector<int> cont3(64 * 64 * 64, 10);
	array<int, 3> arr3(64, 64, 64, cont3.begin());
	
    int res;
	
    res &= VerifyCpuAccessType(arr1, access_type_read_write);
    res &= VerifyCpuAccessType(arr2, access_type_read_write);
    res &= VerifyCpuAccessType(arr3, access_type_read_write);
	
	return res;
}

int test6()
{
	std::vector<int> cont1(64, 10);
	array<int, 1> arr1(64, cont1.begin(), cont1.end());
	
	std::vector<int> cont2(64 * 64, 10);
	array<int, 2> arr2(64, 64, cont2.begin(), cont2.end());
	
	std::vector<int> cont3(64 * 64 * 64, 10);
	array<int, 3> arr3(64, 64, 64, cont3.begin(), cont3.end());
	
    int res;
	
    res &= VerifyCpuAccessType(arr1, access_type_read_write);
    res &= VerifyCpuAccessType(arr2, access_type_read_write);
    res &= VerifyCpuAccessType(arr3, access_type_read_write);
	
	return res;
}

int test7()
{
	extent<3> arr_extent = CreateRandomExtent<3>(64);
	
	array_view<int , 3> arr_v(arr_extent);
	array_view<const int, 3> arr_v_c(arr_v);
	array<int, 3> arr(arr_v_c);
	
    return VerifyCpuAccessType(arr, access_type_read_write);
}

int test8(accelerator& device)
{
	extent<2> arr_extent = CreateRandomExtent<2>(64);
	
	array_view<int , 2> arr_v(arr_extent);
	array_view<const int, 2> arr_v_c(arr_v);
	array<int, 2> arr(arr_v_c, device.get_default_view(), access_type_read_write);
	
    return VerifyCpuAccessType(arr, access_type_read_write);
}

int test9(accelerator& device)
{
	extent<2> arr_extent = CreateRandomExtent<2>(64);
    array<float, 2> arr(arr_extent, device.get_default_view(), access_type_read_write);
	
    return VerifyCpuAccessType(arr, access_type_read_write);
}

int test10(accelerator& device)
{
	array<int, 1> arr1(64, device.get_default_view(), access_type_read_write);
	array<int, 2> arr2(64, 64, device.get_default_view(), access_type_read_write);
	array<int, 3> arr3(64, 64, 64, device.get_default_view(), access_type_read_write);
	
    int res;
	
    res &= VerifyCpuAccessType(arr1, access_type_read_write);
    res &= VerifyCpuAccessType(arr2, access_type_read_write);
    res &= VerifyCpuAccessType(arr3, access_type_read_write);
	
	return res;
}

int test11(accelerator& device)
{
	extent<3> arr_extent = CreateRandomExtent<3>(64);
	std::vector<int> cont(arr_extent.size(), 10);
	array<int, 3> arr(arr_extent, cont.begin(), device.get_default_view(), access_type_read_write);
	
    return VerifyCpuAccessType(arr, access_type_read_write);
}

int test12(accelerator& device)
{
	extent<2> arr_extent = CreateRandomExtent<2>(64);
	std::vector<int> cont(arr_extent.size(), 10);
	array<int, 2> arr(arr_extent, cont.begin(), cont.end(), device.get_default_view(), access_type_read_write);
	
    return VerifyCpuAccessType(arr, access_type_read_write);
}

int test13(accelerator& device)
{
	std::vector<int> cont1(64, 10);
	array<int, 1> arr1(64, cont1.begin(), device.get_default_view(), access_type_read_write);
	
	std::vector<int> cont2(64 * 64, 10);
	array<int, 2> arr2(64, 64, cont2.begin(), device.get_default_view(), access_type_read_write);
	
	std::vector<int> cont3(64 * 64 * 64, 10);
	array<int, 3> arr3(64, 64, 64, cont3.begin(), device.get_default_view(), access_type_read_write);
	
    int res;
	
    res &= VerifyCpuAccessType(arr1, access_type_read_write);
    res &= VerifyCpuAccessType(arr2, access_type_read_write);
    res &= VerifyCpuAccessType(arr3, access_type_read_write);
	
	return res;
}

int test14(accelerator& device)
{
	std::vector<int> cont1(64, 10);
	array<int, 1> arr1(64, cont1.begin(), cont1.end(), device.get_default_view(), access_type_read_write);
	
	std::vector<int> cont2(64 * 64, 10);
	array<int, 2> arr2(64, 64, cont2.begin(), cont2.end(), device.get_default_view(), access_type_read_write);
	
	std::vector<int> cont3(64 * 64 * 64, 10);
	array<int, 3> arr3(64, 64, 64, cont3.begin(), cont3.end(), device.get_default_view(), access_type_read_write);
	
    int res;
	
    res &= VerifyCpuAccessType(arr1, access_type_read_write);
    res &= VerifyCpuAccessType(arr2, access_type_read_write);
    res &= VerifyCpuAccessType(arr3, access_type_read_write);
	
	return res;
}

int main()
{		
	accelerator device = require_device();
	
	if(!device.get_supports_cpu_shared_memory())
	{
        //WLog() << "The accelerator " << device.get_description() << " does not support zero copy: Skipping" << std::endl;
        return 2;
	}

	accelerator(accelerator::default_accelerator).set_default_cpu_access_type(access_type_read_write);
	
    int res;
	
    res &= test1();
    res &= test2();
    res &= test3();
    res &= test4();
    res &= test5();
    res &= test6();
    res &= test7();
    res &= test8(device);
    res &= test9(device);
    res &= test10(device);
    res &= test11(device);
    res &= test12(device);
    res &= test13(device);
    res &= test14(device);
	
	return res;
}

